#include "WS2812B.h"
#include "timer.h"
#include "fonts.h"	

uint8_t rgb0[1][3] = {0,0,0};           /* 灭 */
uint8_t rgb1[1][3] = {255,0,0};	        /* 红 */
uint8_t rgb2[1][3] = {255,128,0};	    /* 橙 */
uint8_t rgb3[1][3] = {255,255,0};	    /* 黄 */
uint8_t rgb4[1][3] = {0,255,0};	        /* 绿 */
uint8_t rgb5[1][3] = {0,255,255};	    /* 青 */
uint8_t rgb6[1][3] = {0,0,255};	        /* 蓝 */
uint8_t rgb7[1][3] = {128,0,128};	    /* 紫 */
uint8_t rgb8[1][3] = {255,255,255};	    /* 白 */

/* 可容纳一个完整DMA传输的缓冲区
 * 确保这个缓冲区足够大，以容纳
 * 所有需要发送的数据字节
 * 缓冲区的大小可以按以下方式计算。
 * LED的数量 * 24字节 + 42字节
 * 这使得我们的最大字符串长度为
 * (每个DMA流2^16字节-42字节)/每个LED 24字节 = 2728个LED
 */

/************************************************
 TIM2 PA0
************************************************/

#define TIM2_CCR1_Address 0x40000034
#define TIMING_ONE  50
#define TIMING_ZERO 25
uint16_t LED_BYTE_Buffer[12400];

//static sFONT *ws2812_Currentfonts = &Font8x16;  /* 英文字体 */
//---------------------------------------------------------------//
void Timer2_init(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
	
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	TIM_TimeBaseStructure.TIM_Period = 90-1; // 800kHz 
	TIM_TimeBaseStructure.TIM_Prescaler = 0;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
		
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	//开启DMA时钟
	
	DMA_DeInit(DMA1_Channel2);							//设置初始化通道

	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)TIM2_CCR1_Address;				// 外设地址	physical address of Timer 2 CCR1
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)LED_BYTE_Buffer;							// 存储器地址	this is the buffer memory 
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;														// 传输方向，从内存到外设	data shifted from memory to peripheral
	DMA_InitStructure.DMA_BufferSize = 42;																				// 每次循环传输的数据量值
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;							// 外设地址不变
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;												// 内存地址每次加1	automatically increase buffer index
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;		//设置DMA在访问时每次操作的数据长度
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;						// 设置DMA在访问时每次操作的数据长度
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;																	// 设置DMA的传输格式，通用格式 stop DMA feed after buffer size is reached
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;													// 设置DMA的优先级；可以分为4级：VeryHigh，High,Medium,Low
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;																	// 设置DMA的2个memory中的变量互相访问的
	
	DMA_Init(DMA1_Channel2, &DMA_InitStructure);																	//前面那些都是对DMA结构体成员的设置，在次再统一对DMA整个模块做一次初始化，使得DMA各成员与上面的参数一致。

	/* TIM2 CC1 DMA Request enable */
	TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);																			//DMA使能启动
}

void ws2812_DispStringLine_EN_CH ( unsigned char * pStr, 
                                    uint8_t colorflag, 
                                    uint8_t delayflag,
                                    uint8_t disflag )
{
    uint8_t (*color)[3];
	uint16_t usCh;
	uint8_t ucBuffer [ 16*16/8 ];
	uint8_t tBuffer [20][32] ;
	uint8_t flag = 0;
	
	while ( * pStr != '\0' )
	{
		if ( * pStr <= 126 )	           	
		{
            /* 英文字符(等待补充) */
		}
		else	/* 汉字字符 */                            
		{
			usCh = * ( uint16_t * ) pStr;	
			usCh = ( usCh << 8 ) + ( usCh >> 8 );
			//取字模数据  
			ChoiceGetGBK ( ucBuffer, usCh ,disflag );
			TempBuffer ( &ucBuffer, tBuffer, flag );	
			pStr += 2;           //一个汉字两个字节 
		}		
		flag++;
	}
    ChoiceColor(colorflag, color);
	UsChar_LeftDisplay(tBuffer, &color[0], flag, delayflag);
}

void TempBuffer ( uint8_t (*date)[32], uint8_t usTemp[][32], uint8_t flag )
{
	uint8_t a=0;
	
	for(a=0;a<32;a++)	
	{
		usTemp[flag][a] = date[0][a];
	}
}

//根据数组颜色依次显示
void Ws2812_SendusChar(uint8_t (*color)[3], uint16_t len)
{
	uint8_t i,j=0;			//循环标志
	uint16_t memaddr;	    //数组位置标志
	uint16_t buffersize;    //传输字节大小
	buffersize = (len*24)+43;	
	memaddr = 0;				

	while (len)
	{	
		for(i=0; i<8; i++) // GREEN data
		{
			LED_BYTE_Buffer[memaddr] = ((color[j][1]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
			memaddr++;
		}
		for(i=0; i<8; i++) // RED
		{
				LED_BYTE_Buffer[memaddr] = ((color[j][0]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
				memaddr++;
		}
		for(i=0; i<8; i++) // BLUE
		{
				LED_BYTE_Buffer[memaddr] = ((color[j][2]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
				memaddr++;
		}
		len--;
		j++;
	}
    //===================================================================//	
    //bug：最后一个周期波形不知道为什么全是高电平，故增加一个波形
  	LED_BYTE_Buffer[memaddr] = ((color[0][2]<<8) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
    //===================================================================//	
    memaddr++;	
    while(memaddr < buffersize)
    {
        LED_BYTE_Buffer[memaddr] = 0;
        memaddr++;
    }

    DMA_SetCurrDataCounter(DMA1_Channel2, buffersize); 	// 重新确定每次循环要传输的数据量值 load number of bytes to be transferred
    DMA_Cmd(DMA1_Channel2, ENABLE); 			        // DMA使能 enable DMA channel 2
    TIM_Cmd(TIM2, ENABLE); 						        // 使能TIM2 enable Timer 2
    while(!DMA_GetFlagStatus(DMA1_FLAG_TC2)) ; 	        // 等待DMA传输完成 （DMA1_FLAG_TC2传输完成标志）wait until transfer complete
    TIM_Cmd(TIM2, DISABLE); 					        // 关闭TIM2 disable Timer 2
    DMA_Cmd(DMA1_Channel2, DISABLE); 			        // 关闭DMA disable DMA channel 2
    DMA_ClearFlag(DMA1_FLAG_TC2); 				        // 清除DMA标志 clear DMA1 Channel 2 transfer complete flag
}

void UsChar_LeftDisplay( uint8_t (*date)[32], 
                         uint8_t (*color)[3], 
                         uint8_t num, 
                         uint8_t delayflag)//汉字左移 date汉字取模数组，color颜色，num汉字数量,
{
	uint8_t i,j,k,flag,dat,rgb_m = 0,rgb_n = 31;		//i,j循环标志，flag汉字十六进制标志，dat移位临时数组，rgb_m灯定位，rgb_n灯定位
    uint8_t rgb_hz[512][3],cache[2][32];		//rgb_hzRGB显示数组,cache[32]缓存数组
	uint8_t len = 0;				//len汉字长度

	for(i=0;i<32;i++)	
	{
		cache[0][i] = 0x00;
		cache[1][i] = date[0][i];
	}
	while(num - len + 1)
	{
		for(k = 0;k < 17;k++)	/* 单个汉字移位完成 */
		{
			for(i = 0;i < 32;i++)	/* 显示单个汉字 */
			{
				if(i%2 == 0)
				{
					rgb_m = i/2;
					rgb_n = 31-i/2;
				}
				dat = cache[0][i];
				for(j = 0;j < 4;j++)
				{
					flag = dat&0x80;
					if(flag == 0x80)
					{
						rgb_hz[rgb_m][0] = color[0][0];
						rgb_hz[rgb_m][1] = color[0][1];
						rgb_hz[rgb_m][2] = color[0][2];
						rgb_hz[rgb_m+256][0] = color[0][0];
						rgb_hz[rgb_m+256][1] = color[0][1];
						rgb_hz[rgb_m+256][2] = color[0][2];
					}
					else
					{
						rgb_hz[rgb_m][0] = 0;
						rgb_hz[rgb_m][1] = 0;
						rgb_hz[rgb_m][2] = 0;
						rgb_hz[rgb_m+256][0] = 0;
						rgb_hz[rgb_m+256][1] = 0;
						rgb_hz[rgb_m+256][2] = 0;
					}
					rgb_m += 32;
					dat <<= 1;
					
					flag = dat&0x80;
					if(flag == 0x80)
					{
						rgb_hz[rgb_n][0] = color[0][0];
						rgb_hz[rgb_n][1] = color[0][1];
						rgb_hz[rgb_n][2] = color[0][2];
						rgb_hz[rgb_n+256][0] = color[0][0];
						rgb_hz[rgb_n+256][1] = color[0][1];
						rgb_hz[rgb_n+256][2] = color[0][2];
					}
					else
					{
						rgb_hz[rgb_n][0] = 0;
						rgb_hz[rgb_n][1] = 0;
						rgb_hz[rgb_n][2] = 0;
						rgb_hz[rgb_n+256][0] = 0;
						rgb_hz[rgb_n+256][1] = 0;
						rgb_hz[rgb_n+256][2] = 0;
					}
					rgb_n += 32;
					dat <<= 1;
				}
			}
			Ws2812_SendusChar(&rgb_hz[0],512);
			ChoiceSpeed(delayflag);
			
			for(i=0;i<16;i++)	/* 移位 */
			{
				cache[0][2*i] = (cache[0][2*i] <<= 1) | ((cache[0][2*i+1]&0x80) >> 7) ;
				cache[0][2*i+1] = (cache[0][2*i+1] <<= 1) | ((cache[1][2*i]&0x80) >> 7) ;
				cache[1][2*i] = (cache[1][2*i] <<= 1) | ((cache[1][2*i+1]&0x80) >> 7) ;
				cache[1][2*i+1] <<= 1 ;
			}
		}
		len++;
		if(num > 2 && len < num)
		{
			for(i=0;i<32;i++)
			{
				cache[1][i] = date[len][i];
			}
		}
	}
}

void ChoiceColor( uint8_t flag, uint8_t (*color)[3] )
{
    switch (flag)
    {
        case 0:color=rgb0;break;
        case 1:color=rgb1;break;
        case 2:color=rgb2;break;
        case 3:color=rgb3;break;
        case 4:color=rgb4;break;
        case 5:color=rgb5;break;
        case 6:color=rgb6;break;
        case 7:color=rgb7;break;
        case 8:color=rgb8;break;
        default:
            break;
    }
}

void ChoiceSpeed( uint8_t flag )
{
    switch (flag)
    {
        case 1:delay_ms(25);break;
        case 2:delay_ms(50);break;
        case 3:delay_ms(100);break;
        case 4:delay_ms(150);break;
        case 5:delay_ms(200);break;
        default:
            break;
    }
}
